// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... namespace LargoCommon.Music { using System; using System.Collections; using System.Collections.ObjectModel; using System.Diagnostics.Contracts; using System.Text; using System.Xml.Serialization; using Abstract; /// /// Binary Schema. /// [Serializable] [XmlRoot] public class BinarySchema : BinaryStructure { #region Fields /// List of places. private Collection places; /// List of distances. private Collection distances; #endregion #region Constructors /// Initializes a new instance of the BinarySchema class. public BinarySchema() //// resharper - redundant call : base() { } /// /// Initializes a new instance of the BinarySchema class. /// /// The given system. /// Structural code. public BinarySchema(GeneralSystem givenSystem, string structuralCode) : base(givenSystem, structuralCode) { Contract.Requires(givenSystem != null); this.FormalBehavior = new FormalBehavior(); this.RhythmicBehavior = new RhythmicBehavior(); } /// /// Initializes a new instance of the BinarySchema class. /// /// The given system. /// Bit array. public BinarySchema(GeneralSystem givenSystem, BitArray givenBitArray) : base(givenSystem, givenBitArray) { Contract.Requires(givenSystem != null); this.FormalBehavior = new FormalBehavior(); this.RhythmicBehavior = new RhythmicBehavior(); } /// /// Initializes a new instance of the BinarySchema class. /// /// The given system. /// Number of structure. public BinarySchema(GeneralSystem givenSystem, long number) : base(givenSystem, number) { this.FormalBehavior = new FormalBehavior(); this.RhythmicBehavior = new RhythmicBehavior(); } /// Initializes a new instance of the BinarySchema class. /// Binary structure. public BinarySchema(BinaryStructure structure) : base(structure) { Contract.Requires(structure != null); this.FormalBehavior = new FormalBehavior(); this.RhythmicBehavior = new RhythmicBehavior(); } #endregion #region Properties /// Gets order of system. /// Property description. public byte Order => this.GSystem.Order; /// Gets schema of positions. /// Property description. public string PosSchema => this.PlaceString(); /// Gets binary schema of elements. /// Property description. [XmlAttribute] public virtual string ElementSchema { get { var s = new StringBuilder(); for (byte e = 0; e < this.GSystem.Order; e++) { s.Append(this.IsOn(e) ? '1' : '0'); } //// string se = (from e in Enumerable.Range(0, this.GSystem.Order).Cast() //// select this.IsOn(e) ? "1":"0") .Aggregate((current, next) => current + ", " + next); */ return s.ToString().Trim(); } } #endregion #region Places and distances /// Gets positions of nonzero bits. /// Property description. [XmlIgnore] public Collection Places { get { Contract.Ensures(Contract.Result>() != null); if (this.places == null) { this.places = this.BitPlaces; } //// if (this.places == null) { //// throw new InvalidOperationException("List of places is null."); } return new Collection(this.places); } } /// Gets distances of nonzero bits. /// Property description. [XmlIgnore] public Collection Distances { get { Contract.Ensures(Contract.Result>() != null); if (this.distances == null) { this.distances = this.BitDistances; } if (this.distances == null) { throw new InvalidOperationException("List of distances is null."); } return new Collection(this.distances); } } /// Gets or sets Tone Level. /// Property description. public byte ToneLevel { get; set; } /// Gets measure of rhythmical motion. /// Property description. public float Mobility => this.Properties.ContainsKey(GenProperty.FormalMobility) ? this.Properties[GenProperty.FormalMobility] : 0f; /// Gets measure of rhythmical density. /// Property description. public float Filling => this.Properties.ContainsKey(GenProperty.FormalFilling) ? this.Properties[GenProperty.FormalFilling] : 0f; /// Gets measure of rhythmical regularity. /// Property description. public float Variance => this.Properties.ContainsKey(GenProperty.FormalVariance) ? this.Properties[GenProperty.FormalVariance] : 0f; /// Gets measure of rhythmical beat. /// Property description. public float Beat => this.Properties.ContainsKey(GenProperty.FormalBeat) ? this.Properties[GenProperty.FormalBeat] : 0f; /// Gets measure of rhythmical balance. /// Property description. public float Balance => this.Properties.ContainsKey(GenProperty.FormalBalance) ? this.Properties[GenProperty.FormalBalance] : 0f; /// Gets measure of rhythmical complexity. /// Property description. public float Complexity => this.Properties.ContainsKey(GenProperty.FormalComplexity) ? this.Properties[GenProperty.FormalComplexity] : 0f; /// Gets list of nonzero bits distances. /// Property description. /// Returns value. public string DistanceSchema { get { var s = new StringBuilder(); s.Append("("); for (byte lev = 0; lev < this.Level; lev++) { var p = (lev == this.Level - 1) ? string.Empty : ","; if (lev > 0 && lev < this.Distances.Count) { s.Append(this.Distances[lev] + p); } } s.Append(")"); return s.ToString(); } } #endregion #region Properties - Behavior /// /// Gets or sets the harmonic behavior. /// /// /// The harmonic behavior. /// public FormalBehavior FormalBehavior { get; set; } /// /// Gets or sets the harmonic behavior. /// /// /// The harmonic behavior. /// public RhythmicBehavior RhythmicBehavior { get; set; } #endregion #region Public methods /// Makes a deep copy of the BinarySchema object. /// Returns object. public override object Clone() { return new BinarySchema(this.GSystem, this.GetStructuralCode); } /// Formal position of the given nonzero bit. /// Requested formal level. /// Returns value. public byte PlaceAtLevel(byte level) { if (level >= this.Places.Count) { throw new ArgumentException("Incorrect level"); } return this.Places[level]; } /// Real position of the given nonzero bit. /// Requested real level. /// Returns value. public short RealPlaceAtLevel(short level) { short p = 0; if (this.Level == 0) { return p; } while (level < 0) { level += this.Level; p -= this.GSystem.Order; } while (level >= this.Level) { level -= this.Level; p += this.GSystem.Order; } var idx = level % this.Level; if (idx < this.Places.Count) { p += this.Places[idx]; } return p; } /// Distance of bit pair on given Level. /// Requested level. /// Returns value. public byte DistanceAtLevel(byte level) { if (level >= this.Distances.Count) { throw new ArgumentException("Incorrect level"); } return (byte)(level < this.Level ? this.Distances[level] : 0); } /// /// Range of bit pair on given Level. /// /// The given level. /// /// Returns value. /// public BitRange RangeAtLevel(byte givenLevel) { if (givenLevel >= this.Places.Count) { throw new ArgumentException("Incorrect level"); } if (givenLevel >= this.Level) { return null; } var order = this.GSystem.Order; var place = this.PlaceAtLevel(givenLevel); var length = this.DistanceAtLevel(givenLevel); if (givenLevel == (byte)(this.Level - 1)) { var diff = (short)(place + length - order); if (diff > 0 && diff < length) { length = (byte)(length - diff); } } var range = new BitRange(order, place, length); return range; } /// Range of bit pair on given Level - simplified algorithm. /// Requested level. /// Returns value. public BitRange RangeForLevel(byte level) { if (level >= this.Places.Count) { throw new ArgumentException("Incorrect level"); } var range = new BitRange(this.GSystem.Order, this.PlaceAtLevel(level), this.DistanceAtLevel(level)); return range; } /// Returns frequency ratio of given level. /// Requested level. /// Given level can exceed modality level. /// Returns value. public float RatioForLevel(int level) { Contract.Requires(this.Level != 0); if (level % this.Level >= this.Places.Count) { throw new ArgumentException("Incorrect level"); } var lev = (byte)(level % this.Level); //// if (this.Level <= 0) { return r; } var n = level / this.Level; //// if (this.Order != 0) { //// was r (nonsense) var r = (float)Math.Pow(2, n + ((float)this.PlaceAtLevel(lev) / this.Order)); return r; } /// Returns index of level containing given bit. /// Given element/bit. /// Returns value. public byte LevelContainingBit(byte givenBit) { for (byte lev = 0; lev < this.Level; lev++) { if (this.RangeForLevel(lev).ContainsBit(givenBit)) { return lev; } } return 0; } #endregion #region String representation /// List of nonzero bits places. /// Returns value. public string PlaceString() { var s = new StringBuilder(); for (byte lev = 0; lev < this.Level; lev++) { if (lev >= this.Places.Count) { continue; } s.Append(this.Places[lev]); if (lev < this.Level - 1) { s.Append(","); } } return s.ToString(); } /// String representation of the object. /// Returns object. public override string ToString() { var s = new StringBuilder(base.ToString()); s.Append(" "); s.Append(this.DistanceSchema); return s.ToString(); } #endregion #region Compute properties /// Evaluate and set Rhythmic properties. /// public void ComputeRhythmicProperties() { this.FormalBehavior.Variance = this.ComputeVariance(); this.FormalBehavior.Balance = this.ComputeBalance(); this.RhythmicBehavior.Filling = this.ComputeFilling(); this.RhythmicBehavior.Beat = this.ComputeBeat(); this.RhythmicBehavior.Mobility = this.ComputeMobility(); this.RhythmicBehavior.Complexity = this.ComputeComplexity(); } /// /// Writes the behavior to properties. /// public override void WriteBehaviorToProperties() { if (this.FormalBehavior != null) { this.Properties[GenProperty.FormalBalance] = this.FormalBehavior.Balance; this.Properties[GenProperty.FormalVariance] = this.FormalBehavior.Variance; this.Properties[GenProperty.FormalEntropy] = this.FormalBehavior.Entropy; } if (this.RhythmicBehavior != null) { this.Properties[GenProperty.FormalFilling] = this.RhythmicBehavior.Filling; this.Properties[GenProperty.FormalBeat] = this.RhythmicBehavior.Beat; this.Properties[GenProperty.FormalMobility] = this.RhythmicBehavior.Mobility; this.Properties[GenProperty.FormalComplexity] = this.RhythmicBehavior.Complexity; } } #endregion #region Evaluation of properties /// /// Determine and sets the variance property. /// /// Returns value. public float ComputeVariance() { // variational quotient float variance = 0; if (this.Level > 1) { var md = this.MeanDistance(); var value = 0.0F; for (byte e = 0; e < this.Level; e++) { value = value + (float)Math.Pow( Math.Abs(this.DistanceAtLevel(e) - md), 2.0); } if (this.Level > 0 && md >= DefaultValue.AfterZero && md <= DefaultValue.LargeNumber) { //// Math.Abs(md) > 0.00001 variance = (float)Math.Sqrt(value / this.Level) / md * 100f; // Level-1 } } return variance; } /// /// Determine and sets the complexity. /// /// Returns value. protected float ComputeComplexity() { var complexity = 0f; if (this.Level > 1) { int value = 0, tv = 0; for (byte lev = 0; lev < this.Level; lev++) { var p = this.PlaceAtLevel(lev); if (p <= 0) { continue; } var d = (byte)MathSupport.GreatestCommonDivisor(this.GSystem.Order, p); tv++; if (d < p) { value++; } tv++; if (d == 1) { value++; } } if (tv != 0) { complexity = (float)value / tv * 100.0f; } } return complexity; } /// /// Determine and sets the complexity. /// /// Returns value. protected float ComputeComplexity2() { //// the algorithm is not very good ?! var complexity = 0f; if (this.Level > 1) { long value = this.GSystem.Order; // 1L; for (byte lev = 0; lev < this.Level; lev++) { long p = this.DistanceAtLevel(lev); if (p > 0) { value = (long)MathSupport.LeastCommonMultiple(value, p); } } var denominator = 2.0f * this.GSystem.Order * this.GSystem.Order; complexity = value / denominator * 100.0f; if (complexity > 100) { complexity = 100.0f; } } return complexity; } /// /// Mean distance of nonzero bits. /// /// /// Returns object. /// protected float MeanDistance() { //// Contract.Requires(this.GSystem != null); if (this.Level < 1) { return 1.0F; } var value = this.GSystem.Order / (float)this.Level; return value; } /// /// Determine and sets the mobility property. /// /// Returns value. protected float ComputeMobility() { //// float mobility = this.GSystem.Order != 0 ? (Level / (float)this.GSystem.Order) * 100f : 0; var mobility = (this.ToneLevel / (float)this.Level) * 100f; //// this.GSystem.Order > 0 ? (this.ToneLevel / (float)this.Level) * 100f : 0; return mobility; } /// /// Determine and sets the filling property. /// /// Returns value. protected float ComputeFilling() { byte sum = 0; var order = this.GSystem.Order; var isPause = this.IsOn(0); for (byte e = 0; e < order; e++) { if (this.IsOn(e)) { isPause = false; } if (!isPause) { sum++; } } var filling = order != 0 ? 100.0f * sum / order : 0; return filling; } /// /// Determine and sets the side property. /// /// /// Returns value. /// protected float ComputeBalance() { var median = this.GSystem.Median; float left = this.IsOnInRange(0, (byte)(median - 1)); //// Contract.Assume(this.GSystem != null); float right = this.IsOnInRange(median, (byte)(this.GSystem.Order - 1)); var balance = this.Level > 0 ? (DefaultValue.HalfUnit + ((right - left) / this.GSystem.Order)) * 100.0f : 0f; return balance; } /// /// Determine and sets the beat property. /// /// Returns value. protected float ComputeBeat() { var beat = 0F; if (this.Level > 0) { float v = 0, tv = 0; var order = this.GSystem.Order; for (byte m = 2; m < order; m++) { if (order % m != 0) { continue; } for (byte e = 0; e < order; e++) { if (e == 1 || e % m != 0) { continue; } float dv = m; if (e < this.BitArray.Count && this.BitArray[e]) { //// = this.IsOn(e) (time optimization) v += dv; } tv += dv; } } if (tv >= DefaultValue.AfterZero && tv <= DefaultValue.LargeNumber) { //// Math.Abs(tv) > 0.0001 beat = v / tv * 100.0f; } } return beat; } /// /// Determine and sets the entropy property. /// /// Returns value. protected float ComputeEntropy() { //// Contract.Assume(this.GSystem != null); var entropy = 0f; if (this.Level > 1) { var value = 0.0f; for (byte lev = 0; lev < this.Level; lev++) { var p = (float)this.DistanceAtLevel(lev) / this.GSystem.Order; if (p > 0) { value = (float)(value + (p * Math.Log(p))); } } var logLevel = (float)Math.Log(this.Level); if (logLevel >= DefaultValue.AfterZero && logLevel <= DefaultValue.LargeNumber) { entropy = -value / logLevel * 100f; } } return entropy; } #endregion } }